package com.mallcloud.mall.app.service.impl;

import cn.hutool.core.map.MapBuilder;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.mallcloud.mall.app.api.constant.ApiConstants;
import com.mallcloud.mall.app.api.entity.dto.XglPartingPaymentDerateDTO;
import com.mallcloud.mall.app.api.entity.vo.XglParkingResponseVO;
import com.mallcloud.mall.app.api.entity.vo.XglPartingPaymentInfoVO;
import com.mallcloud.mall.app.config.ParkConfig;
import com.mallcloud.mall.app.service.AppParkingCouponService;
import com.mallcloud.mall.app.service.AppXglParkingService;
import com.mallcloud.mall.common.core.constant.enums.RLockEnum;
import com.mallcloud.mall.common.core.exception.FailException;
import com.mallcloud.mall.common.core.util.HttpUtil;
import com.mallcloud.mall.mall.api.entity.dto.ParkingPointsPayDiscount;
import com.mallcloud.mall.mall.api.entity.dto.ProXglParkingRedeemRecordReporting;
import com.mallcloud.mall.mall.service.XglParkingRecordService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.TimeUnit;

/**
 * 星光里停车管理
 */
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnProperty("const.park.appId")
public class AppXglParkingServiceImpl implements AppXglParkingService {

	private final HttpUtil httpUtil;
	private final ParkConfig parkConfig;
	private final XglParkingRecordService xglParkingRecordService;
	private final AppParkingCouponService appParkingCouponService;
	private final Redisson redisson;

	@SneakyThrows
	@Override
	public XglPartingPaymentInfoVO getParkingPaymentInfo(String carNumber) {
		Map<String, Object> queryMap = MapUtil.builder(new TreeMap<String, Object>())
				.put("appId", parkConfig.getAppId())
				.put("timestamp", String.valueOf(System.currentTimeMillis()))
				.put("parkId", parkConfig.getParkId())
				.put("carNumber", carNumber)
				.build();
		//固定加密参数
		setSign(queryMap);

		log.info("请求参数: {}", JSONUtil.toJsonStr(queryMap));
		XglParkingResponseVO responseVO = httpUtil.exchange(
				ApiConstants.XglApi.PRICE.getUrl(),
				ApiConstants.XglApi.PRICE.getMethod(),
				null,
				queryMap,
				null,
				ApiConstants.XglApi.PRICE.getResponseClass()
		);
		log.info("停车费返回: {}", JSONObject.toJSONString(responseVO));
		if (!responseVO.isSuccess()) {
			throw new FailException(responseVO.getMessage());
		}
		return JSONObject.toJavaObject(responseVO.getData(), XglPartingPaymentInfoVO.class);
	}

	@SneakyThrows
	@Override
	public Boolean derate(XglPartingPaymentDerateDTO dto) {
		Map<String, Object> requestMap = MapUtil.builder(new TreeMap<String, Object>())
				.put("appId", parkConfig.getAppId())
				.put("timestamp", String.valueOf(System.currentTimeMillis()))
				.put("parkId", parkConfig.getParkId())
				.put("carNumber", dto.getCarNumber())
				//0：全免、1：根据时长减免、2：根据费用减免  3：多次全免 必传
				.put("type", "1")
				.put("derateAmount", dto.getDerateAmount().toString())
				.build();
		//固定加密参数
		setSign(requestMap);

		log.info("请求参数: {}", JSONUtil.toJsonStr(requestMap));
		XglParkingResponseVO responseVO = httpUtil.exchange(
				ApiConstants.XglApi.DERATE.getUrl(),
				ApiConstants.XglApi.DERATE.getMethod(),
				MapBuilder.create(new HashMap<String, String>())
						.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
						.build(),
				null,
				JSONObject.toJSONString(requestMap),
				ApiConstants.XglApi.DERATE.getResponseClass()
		);
		log.info("停车减免返回: {}", JSONObject.toJSONString(responseVO));
		if (!responseVO.isSuccess()) {
			throw new FailException(responseVO.getMessage());
		}
		return Boolean.TRUE;
	}

	/**
	 * 固定加密参数
	 *
	 * @param map
	 */
	private void setSign(Map<String, Object> map) {
		String timestamp = map.get("timestamp").toString();
		String fixedSign = StrUtil.format("appId{}timestamp{}appSecret{}", parkConfig.getAppId(), timestamp, parkConfig.getAppSecret());
		String sortJoin = MapUtil.sortJoin(MapUtil.filter(map, t -> !StrUtil.equalsAnyIgnoreCase(t.getKey(), new String[]{"sign", "appId", "timestamp"})), "", "", true);
		map.put("sign", SecureUtil.md5(fixedSign + sortJoin).toUpperCase());
	}

	@Transactional(rollbackFor = Exception.class)
	@SneakyThrows
	@Override
	public Boolean redeem(ProXglParkingRedeemRecordReporting dto) {
		RLock lock = redisson.getLock(RLockEnum.XGL_PARKING_REDEEM_RECORD_REPORTING.getKey(dto.getPlateNo()));
		//尝试加锁，最多等待5秒，上锁以后10秒自动解锁
		boolean tryLock = lock.tryLock(5, 10, TimeUnit.SECONDS);
		if (!tryLock) {
			throw new FailException("服务繁忙");
		}
		try {
			//停车费积分抵扣
			ParkingPointsPayDiscount proXGLParkRedeem = new ParkingPointsPayDiscount();
			proXGLParkRedeem.setStoreNo(dto.getStoreNo());
			proXGLParkRedeem.setCardNo(dto.getCardNo());
			proXGLParkRedeem.setDiscountPoints(dto.getRedeemPoints());
			appParkingCouponService.parkingPointsDiscount(proXGLParkRedeem);

			//停车券兑换记录上报
			xglParkingRecordService.ProXglParkingRedeemRecordReporting(dto);

			//减免
			XglPartingPaymentDerateDTO derateDto = new XglPartingPaymentDerateDTO();
			derateDto.setCarNumber(dto.getPlateNo());
			derateDto.setDerateAmount(BigDecimal.valueOf(Double.parseDouble(dto.getRedeemDuration())).multiply(BigDecimal.valueOf(60)));
			derate(derateDto);
			return Boolean.TRUE;
		}
		finally {
			lock.unlock();
		}
	}

	@SneakyThrows
	public static void main(String[] args) {
		HttpUtil httpUtil = new HttpUtil();

		String appId = "8lpocuxX21n5syRj84VBofY7OC2defGS";
		String parkId = "1480466537660116994";
		String appSecret = "zGsljr3iok4INyA4Ii3HufEpxfgnBnZw";

		String timestamp = String.valueOf(System.currentTimeMillis());
		Map<String, Object> map = MapUtil.builder(new TreeMap<String, Object>())
				.put("appId", appId)
				.put("timestamp", timestamp)
				.put("parkId", parkId)
				.put("stime", "1673280000")
				.put("etime", "1673315966")
				.put("pageSize", "10")
				.put("pageNum", "1")
				.build();

		//固定加密参数
		String fixedSign = StrUtil.format("appId{}timestamp{}appSecret{}", appId, timestamp, appSecret);
		String sortJoin = MapUtil.sortJoin(MapUtil.filter(map, t -> !StrUtil.equalsAnyIgnoreCase(t.getKey(), new String[]{"sign", "appId", "timestamp"})), "", "", true);
		map.put("sign", SecureUtil.md5(fixedSign + sortJoin).toUpperCase());

		log.info("请求参数: {}", JSONUtil.toJsonStr(map));
		XglParkingResponseVO responseVO = httpUtil.exchange(
				ApiConstants.XglApi.INORDER.getUrl(),
				ApiConstants.XglApi.INORDER.getMethod(),
				null,
				map,
				null,
				ApiConstants.XglApi.INORDER.getResponseClass()
		);
		log.info("请求返回: {}", JSONObject.toJSONString(responseVO));
		if (!responseVO.isSuccess()) {
			throw new FailException(responseVO.getMessage());
		}
		JSONObject.toJavaObject(responseVO.getData(), XglPartingPaymentInfoVO.class);

	}
}
